home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 276-300 / 283 / bref / bref.c < prev    next >
C/C++ Source or Header  |  1995-03-14  |  21KB  |  814 lines

  1. /*   bref - AmigaBASIC cross referencer */ 
  2.  
  3. char   Version[6] = "V 1.01";    /* November 3, 1989
  4.  
  5. **    This program reads standard input OR one or more files
  6. **    and prints the file(s) with line numbers added plus an
  7. **      alphabetic list of word references by line number.
  8. **
  9. **    To run:
  10. **   bref [-Q] [-Lnnn] [-Wnnn] [-Hccc] [-?] [-S] [-K] [-E] [file...]
  11. **
  12. **    Where 'file' must be ASCII, not binary -- AmigaBasic default.
  13. **    To save a Basic program in ASCII, enter in Basic output window:
  14. **        SAVE "prog.name",A
  15. **
  16. **    Options--first letter can be upper or lower case:
  17.  
  18. **    -Q    - don't print normal input file listing (Quiet).
  19. **    -Lnnn - set page Length to n instead of the default 66.
  20. **    -Wnnn - set page Width to n instead of the default 80.
  21. **         Maximum permitted page width is 132.
  22. **    -Hccc - set page Heading to 'ccc' rather than file names.
  23. **    -S    - Suppress form feeds; use for screen output
  24. **    -K    - show BASIC Keywords in crossref table
  25. **    -E    - print the input file 12 chars/in (Elite).  Default 10 cpi.
  26. **      -?    - display this list.
  27. **
  28. **  Compiled with Manx Aztec C:
  29. **    cc bref.c
  30. **    ln bref.o -lc
  31. **
  32. **--------------------------------------------------------------------
  33. **    Program bref is a modification of cref, the C cross referencer
  34. **
  35. **        History -- cref and bref
  36. **    May 1981  Mike Edmonds wrote cref, a cross ref for C language
  37. **    Sept 1987 Joel Swank ported cref to the Amiga
  38. **         1989 Dick Taylor modified cref to produce bref for BASIC
  39. **
  40. **    Dick Taylor            Found a bug?
  41. **    99 Valley View Rd        Want a program change?
  42. **    Glastonbury CT 06033 USA    Editorial remarks?
  43. **    Tel (203) 633-0100        Your comments are welcome!!!
  44. */
  45.  
  46. #include <stdio.h>
  47. #include <ctype.h>
  48. #include <signal.h>
  49. #include <exec/types.h>
  50. #include <stat.h>
  51.  
  52. #define MAXWORD        15    /* maximum chars in word */
  53. #define MAXPAGLINES    999    /* maximum posible lines in page */
  54. #define MINPAGLINES    4    /* minimum posible lines in page */
  55. #define MAXLINWIDTH    132    /* maximum posible chars in line */
  56. #define MINLINWIDTH    MAXWORD+12  /* minimum posible chars in line */
  57. #define MAXTABSIZE    132    /* maximum posible chars in tab */
  58. #define MINTABSIZE    1    /* minimum posible chars in tab */
  59.  
  60. #define igncase(c)    (isupper(c)? tolower(c) : (c))
  61.  
  62. #undef FALSE
  63. #undef TRUE
  64. #define FALSE    0
  65. #define TRUE    1
  66.  
  67. #ifdef    DEBUG
  68. #define debug(a,b)    fprintf(stderr,(a),(b))
  69. #else
  70. #define debug(a,b)
  71. #endif
  72.  
  73.  
  74. /*  global structures*/
  75.  
  76. #define LINLIST    struct    _linlist
  77. #define WRDLIST    struct    _wrdlist
  78.  
  79. struct    _linlist {        /* line number list node */
  80.     long     ln_no ;      /* line number */
  81.     LINLIST    *ln_next ;      /* next element pointer (or NULL) */
  82. } ;
  83.  
  84. struct    _wrdlist {        /* word list node */
  85.     char    *wd_wd ;      /* pointer to word */
  86.     char    *wd_lwd ;      /* pointer to word (lower case) */
  87.     LINLIST     wd_ln ;      /* first element of line list */
  88.     WRDLIST    *wd_low ;      /* lower child */
  89.     WRDLIST    *wd_hi ;      /* higher child */
  90. } ;
  91.  
  92.  
  93. /*  options*/
  94.  
  95. char    *Progname ;
  96. int     Quiet = FALSE ;    /* don't print input file listing? (-q) */
  97. int     Maxpaglines = 66 ;    /* maximum lines in page (-l) */
  98. int     Maxlinwidth = 80 ;    /* default chars in print line (-w) */
  99. int      Tabsize    = 8 ;    /* default length of tab */
  100. int      FormFeed    = TRUE;    /* Suppress form feeds? (-S) */
  101. int     ShowKeyWords = FALSE;  /* Show BASIC keywords in table? (-K)*/
  102. int     Elite         = FALSE;    /* Print source code in elite? (-E) */
  103.  
  104. /*  global variables*/
  105.  
  106. char     Brefhdr[MAXLINWIDTH+1] ;/* report header */
  107. char    *Filename ;        /* name of current input file */
  108. char     Date[30] ;        /* current or last file modify date */
  109. long     Hiline = 1L ;    /* current (and max.) input file line number */
  110. int         files=0 ;      /* count of source files */
  111. WRDLIST    *Wdtree = NULL ;   /* ptr to root node of binary word list */
  112. int     SkipToEOL  = FALSE;   /* Skip to EOL for REM, DATA */
  113. int     SaveMLW;        /* Save Max line width */
  114.  
  115. /*  AmigaBASIC language reserved keywords */
  116. /*  Entered in binary search order.  This minimizes recursion */
  117. /*  during store of the keywords in the tree, thereby conserving on */
  118. /*  Stack usage. If the keywords are entered in alphabetic order, it */
  119. /*  causes a system crash (exceed Stack) during keyword store in the*/
  120. /*  tree.  There are 202 keywords in this list. */
  121.  
  122. char    *Bkeywords[] = {
  123.  
  124. /* Level 1 -- #101 */  "MOUSE",
  125. /* Level 2 -- #50 & #151 */  "EOF", "RESUME",
  126. /* Level 3 -- #25 75 126 177 */ "COLOR", "INT", "OPTION", "SUB",
  127. /* Level 4 */ 
  128. "BREAK", "DECLARE", "FRE","LOF","OBJECT.PLANES","POKEW","SIN","UCASE$",
  129. /* Level 5 */
  130. "AREAFILL", "CINT", "CVD",  "DEFSTR", "EXIT", "IF", "LIBRARY", "MERGE",
  131. "OBJECT.AY","OBJECT.VY", "PEEK", "PTAB","SADD","STATIC","TIME$","WEND",
  132. /* Level 6 */
  133. "AND",  "ATN",  "CHAIN", "CLNG", "COS",  "CVS", "DEFINT",  "EDIT",
  134. "ERL",  "FILES", "GOSUB", "INPUT", "LEFT$", "LLIST", "LPRINT", "MKI$", 
  135. "NEXT", "OBJECT.HIT", "OBJECT.START", "OCT$", "PAINT", "POINT","PRINT",
  136. "READ", "RND", "SCREEN", "SPACE$", "STOP", "TAB", "TRANSLATE$",
  137. "VARPTR", "WINDOW",
  138. /* Level 7 */
  139. "ABS", "APPEND", "AS", "BASE", "CALL", "CHDIR","CIRCLE","CLS","COMMON",
  140. "CSNG", "CVI", "DATA", "DEF", "DEFLNG", "DELETE", "ELSEIF", "EQV",
  141. "ERR", "EXP", "FIX", "FUNCTION", "GOTO", "IMP", "INPUT$",
  142. "KILL", "LEN", "LINE", "LOC", "LOG", "LSET", "MID$", "MKS$", "NAME",
  143. "NOT", "OBJECT.CLIP", "OBJECT.OFF", "OBJECT.PRIORITY", "OBJECT.STOP",
  144. "OBJECT.X", "ON", "OR", "PALETTE", "PEEKL", "POKE", "POS", "PRINT#",
  145. "PUT", "RESET", "RETURN", "RSET", "SAVE", "SGN", "SLEEP", "SPC",
  146. "STEP", "STRIG", "SWAP", "TAN", "TIMER", "TRON", "USING",
  147. "WAIT", "WHILE", "WRITE#",
  148. /* Level 8 -- everything else */
  149. "ALL", "AREA", "ASC", "BEEP", "CDBL", "CHR$", "CLEAR", "CLOSE",
  150. "COLLISION", "CONT", "CSRLIN", "CVL", "DATE$",  "DEFDBL", "DEFSNG",
  151. "DIM","ELSE", "END", "ERASE", "ERROR", "FIELD", "FOR", "GET", "HEX$",
  152. "INKEY$", "INPUT$", "INSTR", "LBOUND", "LET", "LIST", "LOAD",
  153. "LOCATE", "LPOS", "MENU", "MKD$", "MKL$", "MOD", "NEW","OBJECT.AX",
  154. "OBJECT.CLOSE", "OBJECT.ON", "OBJECT.SHAPE",  "OBJECT.VX",
  155. "OBJECT.Y", "OFF", "OPEN", "OUTPUT", "PATTERN", "PEEKW", "POKEL",
  156. "PRESET", "PSET", "RANDOMIZE", "REM", "RESTORE", "RIGHT$", "RUN","SAY",
  157. "SCROLL", "SHARED", "SOUND", "SQR", "STICK", "STR$", "STRING$",
  158. "SYSTEM", "THEN","TO", "TROFF", "UBOUND", "VAL", "WAVE", "WIDTH",
  159. "WRITE", "XOR",
  160.     0
  161. } ;
  162.  
  163.  
  164. /*  main - Store Basic keywords in tree.
  165.  *       Get program options and format heading lines.
  166.  *       Get words/line numbers from input file(s), store in tree.
  167.  *       Retrieve and print words in alphabetic order.  For each
  168.  *        word, print line numbers where word appears. */
  169.  
  170. main(argc, argv)
  171. int     argc ;
  172. char    *argv[] ;
  173. {
  174.     char    wordfilebuf[BUFSIZ] ;
  175.     register FILE    *filep ;
  176.     char    *getword(), *word ;
  177.     struct     stat    stbuf ;
  178.     long     time() ;
  179.     register cnt ;
  180.  
  181.     Progname = *argv ;        /* get options */
  182.     getcmd(argc, argv) ;
  183.         /* If the BASIC keywords are bypassed for the output */
  184.         /*   table, then store keywords in the tree with */
  185.         /*   line count = 0. */
  186.     if (!ShowKeyWords)
  187.         for (cnt=0 ; Bkeywords[cnt] ; cnt++)
  188.         storword(Bkeywords[cnt], 0L) ;
  189.  
  190.     listchr(-2);    /* clear output line */
  191.                     /* read and store files */
  192.     for (cnt=1 ; cnt < argc ; cnt++)
  193.         if (*argv[cnt] != '-')
  194.         {    files++ ;
  195.             Filename = argv[cnt] ;
  196.             if ((filep = fopen(Filename, "r")) == NULL)
  197.                 fatal("can't open %s", Filename) ;
  198.             stat(Filename, &stbuf) ;
  199.             mkdate((long)stbuf.st_mtime) ;
  200.             while (word = getword(filep))
  201.                { storword(word, Hiline);
  202.                  if (strcmp(word,"REM") == 0 ||
  203.                  strcmp(word,"DATA") == 0)
  204.                      SkipToEOL = TRUE;
  205.                }
  206.             fclose(filep) ;
  207.         }
  208.  
  209.     if (!files)            /* no files - read stdin */
  210.     {    if (*Brefhdr)
  211.             Filename = Brefhdr ;
  212.         else
  213.             Filename = "stdin" ;
  214.         mkdate(time( (long *)0)) ;
  215.         while (word = getword(stdin))
  216.             storword(word, Hiline) ;
  217.     }
  218.  
  219.     /*  print cross reference report */
  220.     bref(Wdtree) ;
  221.     exit(0) ;
  222. }
  223.  
  224.  
  225. /*  getcmd - get arguments from command line & build page headings*/
  226.  
  227. getcmd(argc, argv)
  228. register argc ;
  229. register char    *argv[] ;
  230. {
  231.    register cnt ;
  232.  
  233.    debug("GETCMD(%d", argc) ;
  234.    debug(", %s)\n", argv[0]) ;
  235.  
  236.    *Brefhdr = '\0' ;
  237.                     /* get command options */
  238.    for (cnt=1; cnt < argc; cnt++)
  239.    {   if (*argv[cnt] == '-')
  240.        {   switch(igncase(argv[cnt][1]))
  241.        {  case 'q':
  242.         Quiet = TRUE ;
  243.         break ;
  244.  
  245.           case 'l':
  246.         Maxpaglines = atoi(&argv[cnt][2]) ;
  247.         if (Maxpaglines < MINPAGLINES
  248.             || Maxpaglines > MAXPAGLINES)
  249.             fatal("Bad -l value: %s", argv[cnt]) ;
  250.         break ;
  251.  
  252.           case 'w':
  253.         Maxlinwidth = atoi(&argv[cnt][2]) ;
  254.         if (Maxlinwidth < MINLINWIDTH
  255.             || Maxlinwidth > MAXLINWIDTH)
  256.             fatal("Bad -w value: %s", argv[cnt]) ;
  257.         break ;
  258.  
  259.           case 's':
  260.         FormFeed = FALSE;    /* Suppress form feeds */
  261.         break;
  262.  
  263.           case 'k':
  264.         ShowKeyWords = TRUE;   /* Show BASIC keywords */
  265.         break;
  266.  
  267.           case 'e':
  268.         Elite = TRUE;
  269.         printf ("%s", "w");  /* Send elite code to printer*/
  270.         break;
  271.  
  272.           case 'h':
  273.         strncpy(Brefhdr, &argv[cnt][2], MAXLINWIDTH) ;
  274.         Brefhdr[MAXLINWIDTH] = '\0' ;
  275.         break ;
  276.  
  277.           case '?':                /* help option */
  278.         usage();
  279.     printf(" Options--1st letter either upper or lower case:\n\n");
  280.     printf(" -Q    - don't print input file listing (Quiet)\n");
  281.     printf(" -Lnnn - set page Length to n, not default 66.\n");
  282.     printf(" -Wnnn - set page Width to n, not default 80.\n");
  283.     printf(" -Hccc - set page Heading 'ccc', not file names\n");
  284.     printf(" -S    - Suppress form feeds; use--screen output\n");
  285.     printf(" -K    - show BASIC Keywords in CrossRef table\n");
  286.     printf(" -E    - print input file 12 chars/inch (Elite)\n");
  287.     printf(" -?    - display this list.\n");
  288.         exit(0);
  289.  
  290.           default:
  291.         usage();
  292.         exit(0);
  293.        }
  294.        }
  295.    }
  296.  
  297.     if (Elite)
  298.        { SaveMLW = Maxlinwidth;        /* Save Max Line Width */
  299.      Maxlinwidth = (Maxlinwidth * 6) / 5; /* New Max Line Width*/
  300.     }
  301.                 /* insert file names in hdr */
  302.    if (!*Brefhdr)
  303.        for (cnt=1; cnt < argc; cnt++)
  304.         if (*argv[cnt] != '-')
  305.            strjoin(Brefhdr, ' ', argv[cnt], MAXLINWIDTH) ;
  306. }
  307.  
  308. usage()
  309. {
  310. printf("usage:\n\n");
  311. printf("bref [-Q] [-Lnnn] [-Wnnn] [-Hheading] [-S] [-K] [-E] \
  312. [-?] [file ...]\n\n");
  313. }
  314.  
  315. /*  getword - read, print and return next word from file*/
  316.  
  317. char *
  318. getword(filep)
  319. FILE    *filep ;
  320. {    static   int    first_read = TRUE;
  321.     static     char    wordbuf[MAXWORD+1] ;
  322.     register char    *wp = wordbuf ;
  323.     register maxw = sizeof(wordbuf) ;
  324.     register chr ;
  325.     int     inword=0, lastchr=0 ;
  326.     long     slineno ;
  327.  
  328. #define    _listchr(chr)    if (!Quiet) listchr(chr)
  329.  
  330. #define    _rtrnwrd(wp)         \
  331.    {   ungetc(chr, filep) ;    \
  332.        *(wp) = '\0' ;        \
  333.        return wordbuf ;            \
  334.    }
  335.  
  336.    while ((chr = getc(filep)) != EOF)
  337.    {
  338.     if (first_read)
  339.      {first_read = FALSE;
  340.       if (chr == 0xf5)
  341.        fatal ("File %s is binary, can't process--ASCII req.",Filename);
  342.      }
  343.  
  344.      if (SkipToEOL) goto REM_DATA;  /* REM, DATA--skip to end of line*/
  345.         /* normal char - add to current word */
  346.        if ((chr <= 'z' && chr >= 'a') || 
  347.        (chr <= 'Z' && chr >= 'A') )
  348.        {
  349.        if (maxw-- <= 1)
  350.         _rtrnwrd(wp) ;
  351.        *wp++ = chr ;
  352.        inword++ ;
  353.        _listchr(chr) ;
  354.        }
  355.  
  356.        else switch (chr)
  357.        {
  358.             /* These can't be 1st char in word -- */
  359.               /*   digit, period, suffixes for variable type */
  360.       case '0': case '1': case '2': case '3': case '4':
  361.       case '5': case '6': case '7': case '8': case '9':
  362.       case '.': case '%': case '&': case '!': case '#': case '$':
  363.           if (inword)
  364.         {   if (maxw-- <= 1)
  365.             _rtrnwrd(wp) ;
  366.            *wp++ = chr ;
  367.             }
  368.           _listchr(chr) ;
  369.           break ;
  370.                 /* newline - end current word */
  371.       case '\n':
  372.           if (inword)
  373.           _rtrnwrd(wp) ;
  374.           _listchr(chr) ;
  375.           Hiline++ ;
  376.           break ;
  377.             /* Apostrophe (') comment - print & bypass */
  378.                         /*     to end of the line. */
  379.       case '\'':
  380.           if (inword)
  381.           _rtrnwrd(wp) ;
  382. REM_DATA:                 /* Come here for REM & DATA keywords */
  383.           _listchr(chr) ;
  384.           while ((chr = getc(filep)) != EOF)
  385.           {   _listchr(chr);
  386.           if (chr == '\n')
  387.           {   Hiline++;
  388.               SkipToEOL = FALSE;
  389.               break;
  390.           }
  391.           }
  392.           if (chr == EOF)  ungetc(chr, filep);
  393.           break ;
  394.                 /* words in quotes - print & bypass */
  395.       case '"':
  396.           if (inword)
  397.           _rtrnwrd(wp) ;
  398.           _listchr(chr) ;
  399.           while ((chr = getc(filep)) != EOF)
  400.           {   _listchr(chr);
  401.               if (chr == '"')
  402.               break;
  403.           if (chr == '\n')   /* Making assumption here that */
  404.           {   Hiline++;      /* end of line is implied end of*/
  405.               break;         /* quote string. Apparently this*/
  406.           }             /* is what AmigaBasic does. */
  407.           }
  408.           if (chr == EOF) ungetc(chr,filep);
  409.           break ;
  410.  
  411.       default:
  412.           if (inword)
  413.           _rtrnwrd(wp) ;
  414.           _listchr(chr) ;
  415.           break ;
  416.        }        /* End of switch -- process char's */
  417.  
  418.        lastchr = chr ;
  419.    }            /* End of while -- read char's */
  420.  
  421.    if (inword)
  422.        _rtrnwrd(wp) ;
  423.    _listchr(EOF) ;
  424.    return NULL ;
  425. }
  426.  
  427.  
  428. /*  listchr - list the input files one character at a time*/
  429.  
  430. static    Listpage = 0 ;
  431. static    Listpline = MAXPAGLINES ;
  432.  
  433. listchr(chr)
  434. register chr ;
  435. {
  436.     static    char     linebuf[MAXLINWIDTH*2], *lineptr=linebuf ;
  437.     static    lastchr=0, linecnt=0 ;
  438.     static  int    remain;
  439.     static  int    LNWid = 4;   /* Line number width on listing */
  440.             /* Changed from 6 in CREF to 4 in BREF */
  441.  
  442.     if (chr == -2)            /* clear line buffer */
  443.     {    setmem(linebuf,Maxlinwidth,' ');
  444.         return;
  445.     }
  446.  
  447.     if (chr == EOF)            /* EOF - print final line */
  448.     {    *lineptr = '\0' ;
  449.         listline(linebuf) ;
  450.         Listpage = 0 ;
  451.         Listpline = MAXPAGLINES ;
  452.         lineptr = linebuf ;
  453.         linecnt = 0 ;
  454.         return ;
  455.     }
  456.  
  457.     if (lineptr == linebuf)        /* new line - format line number */
  458.     {    ltoc(linebuf, Hiline, LNWid) ;
  459.         lineptr = linebuf + LNWid ;
  460.         *lineptr++ = ' ' ;
  461.         *lineptr++ = ' ' ;
  462.         linecnt = LNWid + 2;
  463.     }
  464.  
  465. #define    _lineoflo(ctr, newctr)        \
  466.     if ((ctr) >= Maxlinwidth)    \
  467.     {    *lineptr = '\0' ;    \
  468.         listline(linebuf) ;    \
  469.         lineptr = &linebuf[LNWid + 2] ;    \
  470.         linecnt = (newctr) ;    \
  471.     }
  472.  
  473.     switch (chr)
  474.     {                /* newline - print last line */
  475.        case '\n':
  476.         if (lastchr != '\f')
  477.         {    *lineptr = '\0' ;
  478.             listline(linebuf) ;
  479.         }
  480.         lineptr = linebuf ;
  481.         linecnt = 0 ;
  482.         break ;
  483.                  /* formfeed - print line and end page*/
  484.        case '\f':
  485.         if (linecnt != LNWid + 2)
  486.         {    *lineptr = '\0' ;
  487.             listline(linebuf) ;
  488.         }
  489.         Listpline = MAXPAGLINES ;  /* This triggers form feed*/
  490.                        /* on next entry--listline*/
  491.         lineptr = linebuf ;
  492.         linecnt = 0 ;
  493.         break ;
  494.                 /* tab - skip to next tab stop */
  495.        case '\t':
  496.         linecnt += Tabsize ;
  497.         remain =  linecnt % Tabsize ;
  498.         linecnt -= remain;
  499.         _lineoflo(linecnt, LNWid + 2) ;
  500.         lineptr += Tabsize ;
  501.         lineptr -= remain;
  502.         break ;
  503.                 /* backspace - print, but don't count*/
  504.        case '\b':
  505.         *lineptr++ = chr ;
  506.         break ;
  507.                     /* ctl-char - print as "^x" */
  508.              case 001: case 002: case 003:
  509.        case 004: case 005: case 006: case 007:
  510.                      case 013:
  511.                  case 015: case 016: case 017:
  512.        case 020: case 021: case 022: case 023:
  513.        case 024: case 025: case 026: case 027:
  514.        case 030: case 031: case 032: case 033:
  515.        case 034: case 035: case 036: case 037:
  516.         _lineoflo(linecnt+=2, LNWid + 4) ;
  517.         *lineptr++ = '^' ;
  518.         *lineptr++ = ('A'-1) + chr ;
  519.         break ;
  520.  
  521.        default:
  522.         if (isprint(chr))
  523.         {    _lineoflo(++linecnt, LNWid + 3) ;
  524.             *lineptr++ = chr ;
  525.         }
  526.         else        /* non-ascii chars - print as "\nnn" */
  527.         {    _lineoflo(linecnt+=4, LNWid + 6) ;
  528.             *lineptr++ = '\\' ;
  529.             *lineptr++ = '0' + ((chr & 0300) >> 6) ;
  530.             *lineptr++ = '0' + ((chr & 070) >> 3) ;
  531.             *lineptr++ = '0' + (chr & 07) ;
  532.         }
  533.         break ;
  534.     }
  535.     lastchr = chr ;
  536. }
  537.  
  538.  
  539.         /* print a completed line from the input file */
  540. listline(line)
  541. register char    *line ;
  542. {
  543.     if (*line)
  544.     {    if (++Listpline >= (Maxpaglines-8))
  545.         {    if (FormFeed)
  546.                 if (files >1 || Listpage) putchar('\f') ;
  547.             printf("\nBREF %s %s %s  Page %d\n\n",
  548.                Version, Date, Filename, ++Listpage) ;
  549.             Listpline = 0 ;
  550.         }
  551.         puts(line) ;
  552.         listchr(-2);    /* clear line buffer */
  553.     }
  554. }
  555.  
  556.  
  557. /*  storword - store word and line # in binary word tree or word file*/
  558.  
  559. storword(word, lineno)
  560. register char    *word ;
  561. long     lineno ;
  562. {
  563.     char     lword[MAXWORD+1] ;
  564.     register char    *cp1, *cp2 ;
  565.     WRDLIST    *addword() ;
  566.  
  567.                 /* convert word to lower case */
  568.     for (cp1=word, cp2=lword ; *cp2++ = igncase(*cp1) ; cp1++)
  569.         ;
  570.  
  571.                     /* store words and lineno */
  572.     Wdtree = addword(Wdtree, word, lword, lineno) ;
  573. }
  574.  
  575.  
  576. /*  addword - add word and line# to in-core word list*/
  577.  
  578. WRDLIST *
  579. addword(wdp, word, lword, lineno)
  580. register WRDLIST *wdp ;
  581. char    *word, *lword ;
  582. long     lineno ;
  583. {
  584.     char    *malloc() ;
  585.     int     comp ;
  586.                     /* insert new word into list */
  587.     if (wdp == NULL)
  588.     {    register wordlen = strlen(word) + 1 ;
  589.  
  590.         wdp = (WRDLIST *)malloc((wordlen * 2)+sizeof(WRDLIST));
  591.         if (wdp == NULL)
  592.             goto nomemory ;
  593.  
  594.         wdp->wd_wd  = (char *)wdp + sizeof(WRDLIST) ;
  595.         wdp->wd_lwd = wdp->wd_wd + wordlen ;
  596.         strcpy(wdp->wd_wd,  word) ;
  597.         strcpy(wdp->wd_lwd, lword) ;
  598.  
  599.         wdp->wd_hi = wdp->wd_low = NULL ;
  600.         wdp->wd_ln.ln_no = lineno ;
  601.         wdp->wd_ln.ln_next = NULL ;
  602.     }
  603.  
  604.                     /* word matched in list? */
  605.     else if (((comp = strcmp(lword, wdp->wd_lwd)) == 0)
  606.           && ((comp = strcmp(word,  wdp->wd_wd))  == 0))
  607.     {    register LINLIST *lnp, **lnpp ;
  608.  
  609.         if (wdp->wd_ln.ln_no)
  610.         {              /* add line# to linked list*/
  611.             lnp = &wdp->wd_ln ;
  612.             do
  613.             {    if (lineno == lnp->ln_no)
  614.                     return wdp ;
  615.                 lnpp = &lnp->ln_next ;
  616.             } while ((lnp = *lnpp) != NULL) ;
  617.  
  618.             *lnpp = (LINLIST *)malloc(sizeof(LINLIST)) ;
  619.             if ((lnp = *lnpp) == NULL)
  620.                 goto nomemory ;
  621.             lnp->ln_no = lineno ;
  622.             lnp->ln_next = NULL ;
  623.         }
  624.     }
  625.  
  626.     else if (comp < 0)    /* search for word in children */
  627.         wdp->wd_low = addword(wdp->wd_low, word, lword,lineno);
  628.     else
  629.         wdp->wd_hi = addword(wdp->wd_hi, word, lword, lineno) ;
  630.  
  631.     return wdp ;
  632.                 /* not enough memory - convert to -b */
  633. nomemory:
  634.     fatal("not enough memory for in-core word list") ;
  635. }
  636.  
  637.  
  638. /*  bref - print cross reference report from internal word list*/
  639.  
  640. #define MAXLNOS 2000        /* maximum line nos. for a word */
  641. long    Linenos[MAXLNOS] ;    /* list of line numbers for a word */
  642.  
  643. bref(wdtree)
  644. register WRDLIST *wdtree ;
  645. {
  646.     if (Elite)
  647.     {printf ("%s","w");   /* Turn off elite for printer */
  648.      Maxlinwidth = SaveMLW;  /* Restore original Max line width*/
  649.     }
  650.  
  651.     breftree(wdtree) ;
  652.     if (FormFeed)
  653.         putchar ('\f'); /*Final form feed after print x-ref table*/
  654. }
  655.  
  656.  
  657. breftree(wdp)            /* recursively print word tree nodes */
  658. register WRDLIST *wdp ;
  659. {
  660.     register LINLIST *lnp ;
  661.     register nos ;
  662.  
  663.     if (wdp != NULL)
  664.     {    breftree(wdp->wd_low) ;    /* print lower children */
  665.  
  666.         nos = 0 ;
  667.         if (Linenos[0] = wdp->wd_ln.ln_no)
  668.         {    lnp = &wdp->wd_ln ;
  669.             while ((lnp = lnp->ln_next) != NULL)
  670.                 if (nos < (MAXLNOS-2))
  671.                     Linenos[++nos] = lnp->ln_no ;
  672.             printword(wdp->wd_wd, nos) ;
  673.         }
  674.  
  675.         breftree(wdp->wd_hi) ;    /* print higher children */
  676.     }
  677. }
  678.  
  679.  
  680. /*  printword - print a word and all its line number references*/
  681.  
  682. printword(word, nos)
  683. char    *word ;
  684. register nos ;
  685. {
  686.     static    firstime=TRUE, linecnt, maxlnos, lnosize ;
  687.     register cnt ;
  688.  
  689.     if (firstime)
  690.     {    firstime = FALSE ;
  691.         linecnt = Maxpaglines ;
  692.         for (lnosize=1 ; Hiline ; lnosize++)
  693.             Hiline /= 10L ;
  694.         maxlnos = (Maxlinwidth - (MAXWORD+7)) / lnosize ;
  695.     }
  696.  
  697.     if (linecnt >= (Maxpaglines - 5))
  698.     {    printheads() ;
  699.         linecnt = 5 ;
  700.     }
  701.  
  702.     printf("%-15s%5d  ", word, ++nos) ;
  703.     Linenos[nos] = 0 ;
  704.  
  705.     for (nos=0, cnt=0 ; Linenos[nos] ; nos++)
  706.     {    if (++cnt > maxlnos)
  707.         {    cnt = 1 ;
  708.             if (linecnt++ >= (Maxpaglines - 4))
  709.             {    printheads() ;
  710.                 linecnt = 5 ;
  711.                 printf("%-15s(cont) ", word);
  712.             }
  713.             else
  714.                 printf("\n%22s", " ") ;
  715.         }
  716.         printf("%*ld", lnosize, Linenos[nos]) ;
  717.     }
  718.     putchar('\n') ;
  719.  
  720.     linecnt++ ;
  721. }
  722.  
  723.  
  724. /*  printheads - print page headings*/
  725.  
  726. printheads()
  727. {
  728.     static    page=0 ;
  729.     long    time() ;
  730.  
  731.     if (!page)
  732.         mkdate(time( (long *)0)) ;
  733.  
  734.     if (FormFeed) putchar('\f') ;        /* Form feed */
  735.     printf("\nBREF %s %s %.*s  Page %d\n\n",
  736.        Version, Date, (Maxlinwidth-36), Brefhdr, ++page) ;
  737.     printf("word             refs    line numbers\n\n") ;
  738. }
  739.  
  740.  
  741. /*  ltoc - store ASCII equivalent of long value in given field*/
  742.  
  743. ltoc(fld, lval, len)
  744. register char    *fld ;
  745. register long    lval ;
  746. register len ;
  747. {
  748.     fld += len ;
  749.     while (len-->0)
  750.         if (lval)
  751.         {    *--fld = '0' + (lval%10L) ;
  752.             lval /= 10L ;
  753.         }
  754.         else
  755.             *--fld = ' ' ;
  756. }
  757.  
  758.  
  759. /*  mkdate - build time/date for use in heading lines*/
  760.  
  761. mkdate(atime)
  762. long    atime ;
  763. {
  764.     long    mtime ;
  765.     char    *cp, *ctime() ;
  766.  
  767.     debug("MKDATE(%ld)\n", atime) ;
  768.  
  769.     mtime = atime ;
  770.     cp = ctime(&mtime) ;
  771.     *(cp+24) = ' ' ;        /* clear newline */
  772.     strcpy(cp+16, cp+19) ;        /* shift over seconds */
  773.     strcpy(Date, cp+4) ;
  774. }
  775.  
  776.  
  777. /*  strjoin - join "str1" to "str2" (separated by "sep")
  778.  *    Truncate if necessary to "max" chars.*/
  779.  
  780. strjoin(str1, sep, str2, max)
  781. register char    *str1, *str2;
  782. char    sep ;
  783. register max ;
  784. {
  785.     if (*str2)
  786.     {    if (*str1)
  787.         {    while (*str1++)
  788.                 if (--max <= 0)
  789.                     goto oflo ;
  790.             max--, str1-- ;
  791.             *str1++ = sep ;
  792.         }
  793.         while (*str1++ = *str2++)
  794.             if (--max <= 0)
  795.                 goto oflo ;
  796.     }
  797.     return ;
  798.  
  799. oflo:
  800.     *--str1 = '\0' ;
  801.     return ;
  802. }
  803.  
  804. /*  fatal - print standard error msg and halt process*/
  805.  
  806. fatal(ptrn, data1, data2)
  807. register char    *ptrn, *data1, *data2 ;
  808. {
  809.     fprintf(stderr, "%s: ", Progname) ;
  810.     fprintf(stderr, ptrn, data1, data2) ;
  811.     putc('\n', stderr) ;
  812.     exit(1);
  813. }
  814.